#include <iostream>
#include <pthread.h>
#include <queue>
using namespace std;
template <class T>
class BlockQueue
{
    static const int defaultCapacity = 20;

private:
    queue<T> BQ;
    pthread_mutex_t mutex;
    pthread_cond_t p_cond;
    pthread_cond_t c_cond;
    int maxcap_;
    // int upper; // 上限极值
    // int under;

public:
    BlockQueue(int maxcap = defaultCapacity) : maxcap_(maxcap)
    {
        // upper = static_cast<int>((maxcap_ * 2) / 3);
        // under = static_cast<int>(maxcap_ / 3);
        pthread_mutex_init(&mutex, NULL);
        pthread_cond_init(&p_cond, NULL);
        pthread_cond_init(&c_cond, NULL);
    };
    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&p_cond);
        pthread_cond_destroy(&c_cond);
    };
    void push(const T &date)
    {
        pthread_mutex_lock(&mutex);

        // if (BQ.size()  == maxcap_) 这种判断可能会出现伪唤醒情况，
        //  即当所有阻塞线程被唤醒，当拿到锁时都可以访问临界资源
        // {
        //    pthread_cond_wait(&p_cond, &mutex);
        // }

        while (BQ.size() == maxcap_)
        {
            pthread_cond_wait(&p_cond, &mutex);
        }

        BQ.push(date);
        // if (BQ.size() >= upper)
        // {
        //     pthread_cond_signal(&c_cond);
        // }
        pthread_cond_signal(&c_cond);
        pthread_mutex_unlock(&mutex);
    }
    T pop()
    {
        pthread_mutex_lock(&mutex);
        while (BQ.size() == 0)
        {
            pthread_cond_wait(&c_cond, &mutex);
        }

        T out = BQ.front();
        BQ.pop();
        // if (BQ.size() < under)
        // {
        //     pthread_cond_signal(&c_cond);
        // }
        pthread_cond_signal(&p_cond);
        pthread_mutex_unlock(&mutex);

        return out;
    }
};
